import Koa from 'koa';
import {isFunction} from 'lodash';
import cmd from './cmd';
import log from './log';
import cfg from './cfg';

const app = new Koa();

// 统一转换旧版本的中间件
const use = app.use;
const convert = require('koa-convert');
app.use = x => use.call(app, convert(x));

// 错误处理
import {error, ext} from './util/koa-ext';
app.use(error({log}));

// 日志记录
if (cfg.dev) {
    app.use(require('koa-logger')());
} else {
    app.use(require('koa-log4js')());
}

// 静态文件
if (cfg.root) {
    // 前端刷新
    app.use(async(ctx, next) => {
        // 对于非api非文件的GET请求视为刷新前端路由
        if (ctx.method === 'GET' &&
            ctx.path.indexOf('.') < 0 &&
            ctx.path !== cfg.api && !ctx.path.startsWith(cfg.apiPrefix)) {
            // 后台只需返回主页
            ctx.path = cfg.index;
        }
        await next();
    });

    app.use(require('koa-static-cache')(
        cfg.root, cfg.file
    ));
}

// 内容解析
app.body = convert(require('koa-body')({
    ...cfg.body, patchNode: true
}));
app.use(app.body);

// JSON调试
if (cfg.dev) {
    app.use(require('koa-json')());
}

// 身份认证
import jwt from './util/koa-jwt';
if (cfg.auth) {
    const secret = cfg.auth;
    app.auth = jwt({secret});
    app.secret = secret;
}

// 功能扩展
app.use(ext());

// 路由定义
import Router from 'koa-router';
import dirs from 'require-dir';
const routes = dirs('./api', {recurse: true});
for (const name in routes) {
    let obj = routes[name];
    if (!isFunction(obj)) { //默认文件夹式路由
        obj = obj.index;
    }
    if (obj) {
        const r = new Router();
        const prefix = `${cfg.api}${name === 'index' ? '' : `/${name}`}`;
        const noAuth = obj(r, app);
        const router = new Router();
        if (!noAuth && app.auth) {
            router.use(app.auth);
        }
        router.use(prefix, r.routes());
        app.use(router.routes());
        log.debug(`+ ${prefix}`);
    }
}

// 启动服务
const server = app.listen(cmd.port || cfg.port, cfg.host, (err) => {
    if (err) {
        log.error(err);
    } else {
        log.info('started at', server.address().port);
    }
});
